/**
* Allows timing of the execution of any block of code.
*/

package org.hackystat.ui.orb.server;

/**
 * A utility Stopwatch class which can provide timings for any section of code.
 * @author David J. Nickles
 *
 */
public final class Stopwatch {
  private long fStart;
  private long fStop;

  private boolean fIsRunning;
  private boolean fHasBeenUsedOnce;
  
  /**
  * Start the stopwatch.
  *
  * @throws IllegalStateException if the stopwatch is already running.
  */
  public void start() {
    if ( this.fIsRunning ) {
      throw new IllegalStateException("Must stop before calling start again.");
    }
    //reset both start and stop
    this.fStart = System.currentTimeMillis();
    this.fStop = 0;
    this.fIsRunning = true;
    this.fHasBeenUsedOnce = true;
  }

  /**
  * Stop the stopwatch.
  *
  * @throws IllegalStateException if the stopwatch is not already running.
  */
  public void stop() {
    if ( !this.fIsRunning ) {
      throw new IllegalStateException("Cannot stop if not currently running.");
    }
    this.fStop = System.currentTimeMillis();
    this.fIsRunning = false;
  }

  /**
  * Express the "reading" on the stopwatch.
  *
  * @throws IllegalStateException if the Stopwatch has never been used,
  * or if the stopwatch is still running.
  * @return the current milliseconds readout from this stopwatch instance
  */
  public String toString() {
    validateIsReadable();
    StringBuffer result = new StringBuffer();
    result.append(this.toValue());
    result.append(" ms");
    return result.toString();
  }

  /**
  * Express the "reading" on the stopwatch as a numeric type.
  *
  * @throws IllegalStateException if the Stopwatch has never been used,
  * or if the stopwatch is still running.
  * @return the current milliseconds readout from this stopwatch instance
  */
  public long toValue() {
    validateIsReadable();
    return this.fStop - this.fStart;
  }

  /**
  * Throws IllegalStateException if the watch has never been started,
  * or if the watch is still running.
  */
  private void validateIsReadable() {
    if ( fIsRunning ) {
      String message = "Cannot read a stopwatch which is still running.";
      throw new IllegalStateException(message);
    }
    if ( !fHasBeenUsedOnce ) {
      String message = "Cannot read a stopwatch which has never been started.";
      throw new IllegalStateException(message);
    }
  }
}
